<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Basic drawing in PyCairo</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="PyCairo, graphics, 2D vector library, basic drawing, 
line, stroke, fill, dash, line cap, line join">
<meta name="description" content="In this chapter of the PyCairo tutorial, we will
do basic drawing.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Basic drawing in PyCairo</h1>


<p>
In this part of the PyCairo tutorial, we will draw some basic primitives. 
We will draw simple lines, use fill and 
stroke operations, we will talk about dashes, line caps and line joins.
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<h2>Lines</h2>

<p>
Lines are very basic vector objects. To draw a line, we use two method calls. 
The starting point is specified with the <code>move_to()</code> call. 
The ending point of a line is specified with the
<code>line_to()</code> call.
</p>

<pre class="code">
#!/usr/bin/python

'''
ZetCode PyCairo tutorial 

In this program, we connect all mouse
clicks with a line.

author: Jan Bodnar
website: zetcode.com 
last edited: August 2012
'''


from gi.repository import Gtk, Gdk
import cairo


class MouseButtons:
    
    LEFT_BUTTON = 1
    RIGHT_BUTTON = 3
    
    
class Example(Gtk.Window):

    def __init__(self):
        super(Example, self).__init__()
        
        self.init_ui()
        
        
    def init_ui(self):    

        self.darea = Gtk.DrawingArea()
        self.darea.connect("draw", self.on_draw)
        self.darea.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)        
        self.add(self.darea)
        
        self.coords = []
                     
        self.darea.connect("button-press-event", self.on_button_press)

        self.set_title("Lines")
        self.resize(300, 200)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()
        
    
    def on_draw(self, wid, cr):

        cr.set_source_rgb(0, 0, 0)
        cr.set_line_width(0.5)
        
        for i in self.coords:
            for j in self.coords:
                
                cr.move_to(i[0], i[1])
                cr.line_to(j[0], j[1]) 
                cr.stroke()

        del self.coords[:]            
                         
                         
    def on_button_press(self, w, e):
        
        if e.type == Gdk.EventType.BUTTON_PRESS \
            and e.button == MouseButtons.LEFT_BUTTON:
            
            self.coords.append([e.x, e.y])
            
        if e.type == Gdk.EventType.BUTTON_PRESS \
            and e.button == MouseButtons.RIGHT_BUTTON:
            
            self.darea.queue_draw()           
                                                        
    
def main():
    
    app = Example()
    Gtk.main()
        
        
if __name__ == "__main__":    
    main()
</pre>

<p>
In our example, we click randomly on the window with a left mouse button. 
Each click is stored in a list. When we right click on the window, all 
points are connected with every other point in the list. This way we can create
some interesting objects. Additional right click clears the window
and we can create another object.
</p>

<pre class="explanation">
class MouseButtons:
    
    LEFT_BUTTON = 1
    RIGHT_BUTTON = 3
</pre>

<p>
The GTK documentation simply states, that the left mouse button has
number 1, right mouse button number 3. We create a custom class to have some
indentifiers for the mouse buttons.
</p>

<pre class="explanation">
self.darea.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)   
</pre>

<p>
Some events are not enabled by default. Mouse press events are among them. 
Therefore, we need to enable mouse press events. 
</p>

<pre class="explanation">
self.darea.connect("button-press-event", self.on_button_press)
</pre>

<p>
In this code example, we will react to mouse press events.
</p>

<pre class="explanation">
cr.set_source_rgb(0, 0, 0)
cr.set_line_width(0.5)
</pre>

<p>
The lines will be drawn in black ink and will be 0.5 points wide.
</p>

<pre class="explanation">
for i in self.coords:
    for j in self.coords:
        
        cr.move_to(i[0], i[1])
        cr.line_to(j[0], j[1]) 
        cr.stroke()
</pre>

<p>
We connect every point from the list to every other point.
The <code>stroke()</code> call draws the lines.
</p>

<pre class="explanation">
del self.coords[:]    
</pre>

<p>
In the end, all the coordinates are deleted. We can now
create another object. 
</p>

<pre class="explanation">
def on_button_press(self, w, e):
    
    if e.type == Gdk.EventType.BUTTON_PRESS \
        and e.button == MouseButtons.LEFT_BUTTON:
        
        self.coords.append([e.x, e.y])
...
</pre>

<p>
If we press a left mouse button, we add its x, y coordinates
to the self.coords list.
</p>

<pre class="explanation">
if e.type == Gdk.EventType.BUTTON_PRESS \
    and e.button == MouseButtons.RIGHT_BUTTON:
    
    self.darea.queue_draw()
</pre>

<p>
In case of a right mouse button press, we call the <code>queue_draw()</code>
method which redraws the drawing area. All the points are connected
with lines.
</p>

<img src="/img/gfx/pycairo/lines.png" alt="Lines">
<div class="figure">Figure: Lines</div>



<h2>Fill and stroke</h2>

<p>
The stroke operation draws the outlines of shapes and the fill 
operation fills the insides of shapes.
</p>

<pre class="code">
#!/usr/bin/python

'''
ZetCode PyCairo tutorial 

This code example draws a circle
using the PyCairo library.

author: Jan Bodnar
website: zetcode.com 
last edited: August 2012
'''


from gi.repository import Gtk
import cairo
import math


class Example(Gtk.Window):

    def __init__(self):
        super(Example, self).__init__()
        
        self.init_ui()
        
        
    def init_ui(self):    

        darea = Gtk.DrawingArea()
        darea.connect("draw", self.on_draw)
        self.add(darea)

        self.set_title("Fill &amp; stroke")
        self.resize(230, 150)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()
        
    
    def on_draw(self, wid, cr):

        cr.set_line_width(9)
        cr.set_source_rgb(0.7, 0.2, 0.0)
        
        w, h = self.get_size()      

        cr.translate(w/2, h/2)
        cr.arc(0, 0, 50, 0, 2*math.pi)
        cr.stroke_preserve()
        
        cr.set_source_rgb(0.3, 0.4, 0.6)
        cr.fill()
        
    
def main():
    
    app = Example()
    Gtk.main()
        
        
if __name__ == "__main__":    
    main()
</pre>


<p>
In our example, we will draw a circle and fill it with a solid color.
</p>

<pre class="explanation">
import math
</pre>

<p>
This module is needed for the <code>pi</code> constant which is
used to draw a circle.
</p>

<pre class="explanation">
cr.set_line_width(9)
cr.set_source_rgb(0.7, 0.2, 0.0)
</pre>

<p>
We set a line width with the <code>set_line_width()</code> method.
We set the source to some dark red colour using the <code>set_source_rgb()</code>
method. 
</p>

<pre class="explanation">
w, h = self.get_size()     
</pre>

<p>
Here we get the width and height of the window. We will need these 
values to center the circle on the window.
</p>

<pre class="explanation">
cr.translate(w/2, h/2)
cr.arc(0, 0, 50, 0, 2*math.pi)
cr.stroke_preserve()
</pre>

<p>
With the <code>translate()</code> method, we move the drawing origin
to the center of the window. We want our circle to be centered. 
The <code>arc()</code> method adds a new circular path to the cairo
drawing context. Finally, the <code>stroke_preserve()</code> method draws
the outline of the circle. Unlike the <code>stroke()</code> method, 
it also preserves the shape for later drawing.
</p>

<pre class="explanation">
cr.set_source_rgb(0.3, 0.4, 0.6)
cr.fill()
</pre>

<p>
We change a colour for drawing and fill the circle with a new colour
using the <code>fill()</code> method.
</p>

<img src="/img/gfx/pycairo/fillstroke.png" alt="Fill &amp; stroke">
<div class="figure">Figure: Fill &amp; stroke</div>


<h2>Pen dashes</h2>

<p>
Each line can be drawn with a different pen dash. A pen dash defines
the style of the line. The dash pattern is specifed by the <code>set_dash()</code>
method. The pattern is set by the dash list which is a list of floating values.
They set the on and off parts of the dash pattern. The dash is used by the
<code>stroke()</code> method to create a line.
If the number of dashes is 0, dashing is disabled. If the number of dashes
is 1, a symmetric pattern is assumed with alternating on and off portions of
the size specified by the single value in dashes.
</p>

<pre class="code">
def on_draw(self, wid, cr):

    cr.set_source_rgba(0, 0, 0, 1)
    cr.set_line_width(2)

    cr.set_dash([4.0, 21.0, 2.0])

    cr.move_to(40, 30)  
    cr.line_to(250, 30)
    cr.stroke()

    cr.set_dash([14.0, 6.0])

    cr.move_to(40, 50)
    cr.line_to(250, 50)
    cr.stroke()

    cr.set_dash([1.0])

    cr.move_to(40, 70)
    cr.line_to(250, 70)
    cr.stroke()                
</pre>

<p>
We draw three lines in three different pen dashes.
</p>

<pre class="explanation">
cr.set_dash([4.0, 21.0, 2.0])
</pre>

<p>
We have a pattern of three numbers. We have 4 points drawn, 21 not drawn
and 2 drawn. Then 4 points not drawn, 21 points drawn and 2 not drawn.
This pattern takes turns until the end of the line.
</p>

<pre class="explanation">
cr.set_dash([14.0, 6.0])
</pre>

<p>
In this pattern, we have always 14 points drawn, 6 not drawn.
</p>

<pre class="explanation">
cr.set_dash([1.0])
</pre>

<p>
Here we create a pen dash of a symmetric pattern of alternating single on
and off points.
</p>

<img src="/img/gfx/pycairo/pendashes.png" alt="Pen dashes">
<div class="figure">Figure: Pen dashes</div>


<h2>Line caps</h2>

<p>
The line caps are endpoints of lines. 
</p>

<ul>
 <li>cairo.LINE_CAP_BUTT</li> 
 <li>cairo.LINE_CAP_ROUND</li>
 <li>cairo.LINE_CAP_SQUARE</li>
</ul>

<p>
There are three different line cap styles in Cairo.
</p>

<div class="center">
<img src="/img/gfx/pycairo/linecaps.png" alt="Line caps">
<div class="figure">Figure: Square, round and butt caps</div>
</div>

<p>
A line with a <code>cairo.LINE_CAP_SQUARE</code> cap will have a 
different size than a line with a <code>cairo.LINE_CAP_BUTT</code> cap. 
If a line is x units wide, the line with a <code>cairo.LINE_CAP_SQUARE</code> 
cap will be exactly x units greater in size. x/2 units at the beginning 
and x/2 units at the end.
</p>

<pre class="code">
def on_draw(self, wid, cr):

    cr.set_source_rgba(0, 0, 0, 1)
    cr.set_line_width(12)

    cr.set_line_cap(cairo.LINE_CAP_BUTT)
    cr.move_to(30, 50)
    cr.line_to(150, 50)
    cr.stroke()

    cr.set_line_cap(cairo.LINE_CAP_ROUND)
    cr.move_to(30, 90)
    cr.line_to(150, 90)
    cr.stroke()

    cr.set_line_cap(cairo.LINE_CAP_SQUARE)
    cr.move_to(30, 130)
    cr.line_to(150, 130)
    cr.stroke()

    cr.set_line_width(1.5)

    cr.move_to(30, 35)
    cr.line_to(30, 145)
    cr.stroke()

    cr.move_to(150, 35)
    cr.line_to(150, 145)
    cr.stroke()

    cr.move_to(155, 35)
    cr.line_to(155, 145)
    cr.stroke()
</pre>

<p>
The example draws three lines with three different line caps. It will also 
graphically demonstrate the differences in size of the lines by drawing three
additional thin vertical lines.
</p>

<pre class="explanation">
cr.set_line_width(12)
</pre>

<p>
Our lines will be 12 units wide. The default line width is 2.
</p>

<pre class="explanation">
cr.set_line_cap(cairo.LINE_CAP_ROUND)
cr.move_to(30, 90)
cr.line_to(150, 90)
cr.stroke()
</pre>

<p>
Here we draw a horizontal line with a <code>cairo.LINE_CAP_ROUND</code> cap.
</p>

<pre class="explanation">
cr.set_line_width(1.5)

cr.move_to(30, 35)
cr.line_to(30, 145)
cr.stroke()
</pre>

<p>
This is one of the three vertical lines used to demostrate the differences in size.
</p>

<br>
<img src="/img/gfx/pycairo/linecaps2.png" alt="Line caps">
<div class="figure">Figure: Line caps</div>


<h2>Line joins</h2>

<p>
The lines can be joined using three different join styles. 
</p>

<ul>
 <li>cairo.LINE_JOIN_MITER</li> 
 <li>cairo.LINE_JOIN_BEVEL</li>
 <li>cairo.LINE_JOIN_ROUND</li>
</ul>

<div class="center">
<img src="/img/gfx/pycairo/linejoins.jpg" alt="Bevel, Round, Miter line joins">
<div class="figure">Figure: Bevel, Round, Miter line joins</div>
</div>
<br>

<pre class="code">
def on_draw(self, wid, cr):

    cr.set_line_width(14)
    
    cr.rectangle(30, 30, 100, 100)        
    cr.set_line_join(cairo.LINE_JOIN_MITER)
    cr.stroke()

    cr.rectangle(160, 30, 100, 100)
    cr.set_line_join(cairo.LINE_JOIN_BEVEL)
    cr.stroke()

    cr.rectangle(100, 160, 100, 100)
    cr.set_line_join(cairo.LINE_JOIN_ROUND)
    cr.stroke()
</pre>

<p>
In this example, we draw three thick rectangles with various line joins. 
</p>

<pre class="explanation">
cr.set_line_width(14)
</pre>

<p>
The lines are 14 units wide. 
</p>


<pre class="explanation">
cr.rectangle(30, 30, 100, 100)        
cr.set_line_join(cairo.LINE_JOIN_MITER)
cr.stroke()
</pre>

<p>
Here we draw a rectangle with <code>cairo.LINE_JOIN_MITER</code> 
join style.
</p>

<img src="/img/gfx/pycairo/linejoins.png" alt="Line joins">
<div class="figure">Figure: Line joins</div>

<p>
In this chapter of the PyCairo tutorial, we did some basic drawing. 
</p>


<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>
<br>

<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>

<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 2, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>


